
// 使用WeakMap实现数据处理的性能优化
// 作用：以原始数据对象为键，存储不同参数下的归一化结果
// 特性：当原始数据对象被销毁时自动清理缓存，避免内存泄漏
const dataMap = new WeakMap();

// 数据归一化处理：通过normalizeArray函数将任意长度的音频数据适配到目标分辨率
// 参数说明：
//  data：原始音频数据数组（PCM采样值）
//  m：目标数组长度（对应画布宽度）
//  downsamplePeaks：是否启用峰值采样模式（默认平均采样）
//  memoize：是否启用缓存优化
const normalizeArray = (data, m, downsamplePeaks = false, memoize = false) => {
    let cache, mKey, dKey;
    if (memoize) {
        mKey = m.toString();
        dKey = downsamplePeaks.toString();
        cache = dataMap.has(data) ? dataMap.get(data) : {};
        dataMap.set(data, cache);
        cache[mKey] = cache[mKey] || {};
        if (cache[mKey][dKey]) {
            return cache[mKey][dKey];
        }
    }
    const n = data.length;
    const result = new Array(m);
    if (m <= n) {
        // Downsampling
        result.fill(0);
        const count = new Array(m).fill(0);
        for (let i = 0; i < n; i++) {
            const index = Math.floor(i * (m / n));
            if (downsamplePeaks) {
                // take highest result in the set
                result[index] = Math.max(result[index], Math.abs(data[i]));
            } else {
                result[index] += Math.abs(data[i]);
            }
            count[index]++;
        }
        if (!downsamplePeaks) {
            for (let i = 0; i < result.length; i++) {
                result[i] = result[i] / count[i];
            }
        }
    } else {
        for (let i = 0; i < m; i++) {
            const index = (i * (n - 1)) / (m - 1);
            const low = Math.floor(index);
            const high = Math.ceil(index);
            const t = index - low;
            if (high >= n) {
                result[i] = data[n - 1];
            } else {
                result[i] = data[low] * (1 - t) + data[high] * t;
            }
        }
    }
    if (memoize) {
        cache[mKey][dKey] = result;
    }
    return result;
};

// 波形绘制模块：WavRenderer.drawBars方法将归一化数据绘制为Canvas条形图
export const WavRenderer = {
    drawBars: (canvas, ctx, data, color, pointCount = 0, barWidth = 0, barSpacing = 0, center = false) => {
        pointCount = Math.floor(
            Math.min(
                pointCount,
                (canvas.width - barSpacing) / (Math.max(barWidth, 1) + barSpacing)
            )
        );
        if (!pointCount) {
            pointCount = Math.floor(
                (canvas.width - barSpacing) / (Math.max(barWidth, 1) + barSpacing)
            );
        }
        if (!barWidth) {
            barWidth = (canvas.width - barSpacing) / pointCount - barSpacing;
        }
        const points = normalizeArray(data, pointCount, true);
        for (let i = 0; i < pointCount; i++) {
            const amplitude = Math.abs(points[i]);
            const height = Math.max(1, amplitude * canvas.height);
            const x = barSpacing + i * (barWidth + barSpacing);
            const y = center ? (canvas.height - height) / 2 : canvas.height - height;
            ctx.fillStyle = color;
            ctx.fillRect(x, y, barWidth, height);
        }
    },
};